﻿using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;

namespace microp11.rf.tx141bv2
{
    public partial class frmMain : Form
    {
        private TempDecoder decoder;
        private WaveIn waveIn = null;
        private bool formIsClosing;

        private const int sampleRate = 48000;
        private const int channels = 1;
        private const int bitDepth = 16;

        private int block_count;
        private CancellationTokenSource source;

        public frmMain()
        {
            InitializeComponent();
            InitializeAudioSourceCombo();
        }

        private void InitializeAudioSourceCombo()
        {
            waveIn = new WaveIn();
            decoder = new TempDecoder(waveIn);

            Dictionary<int, string> selection = new Dictionary<int, string>();

            int waveInDevices = WaveIn.DeviceCount;
            for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
            {
                WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
                selection.Add(waveInDevice, String.Format("{0}: {1}", waveInDevice, deviceInfo.ProductName));
            }
            selection.Add(100, String.Format("{0}: {1}", 100, "FileSource"));

            cbSource.DataSource = new BindingSource(selection, null);
            cbSource.ValueMember = "Key";
            cbSource.DisplayMember = "Value";
            }

        private void btnStart_Click(object sender, EventArgs e)
        {
            checkBoxSaveToFile.Enabled = false;
            cbSource.Enabled = false;
            btnStart.Enabled = false;
            btnStop.Enabled = true;
            formIsClosing = false;
            block_count = 0;

            decoder.SaveToFile = checkBoxSaveToFile.Checked;

            waveIn.DeviceNumber = ((KeyValuePair<int, string>)cbSource.SelectedItem).Key;
            waveIn.DataAvailable += waveIn_DataAvailable;
            waveIn.RecordingStopped += waveIn_RecordingStopped;

            waveIn.WaveFormat = new WaveFormat(sampleRate, bitDepth, channels);
            waveIn.StartRecording();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            checkBoxSaveToFile.Enabled = true;
            waveIn.StopRecording();
            btnStop.Enabled = false;
        }

        void waveIn_RecordingStopped(object sender, StoppedEventArgs e)
        {
            text.AppendText("Recording stopped. ");

            cbSource.Enabled = true;
            btnStart.Enabled = true;
            btnStop.Enabled = false;
            waveIn.DataAvailable -= waveIn_DataAvailable;
            waveIn.RecordingStopped -= waveIn_RecordingStopped;
        }

        void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (formIsClosing)
            {
                //frmMain.ActiveForm.Close();
                Debug.WriteLine("Form Closing detected 1!");
                return;
            } 
            
            ProcessingStart();
            
            WaveBlock block = new WaveBlock();
            for (int index = 0; index < e.BytesRecorded; index += 2)
            {
                if (formIsClosing)
                {
                    //frmMain.ActiveForm.Close();
                    Debug.WriteLine("Form Closing detected 2!");
                    return;
                }

                short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
                block.Samples.Add(sample);
            }
            ProcessingEnd(block);
        }

        private void ProcessingEnd(WaveBlock block)
        {
            block_count++;

            toolStripBlocks.Text = String.Format("Blocks: {0}", block_count);
            toolStripMax.Text = String.Format("Max: {0}", block.MaxValue);
            toolStripCoef.Text = String.Format("Coef: {0:0.00}", block.Threshold);
            toolStripdB.Text = String.Format("dB: {0:0.00}", block.Decibels);
            
            int progressValue = (int)block.Decibels + 40;
            if (progressValue > 15)
                progressValue = 15;

            if (progressValue < 0)
                progressValue = 0;

            progressdB.Value = progressValue;

            decoder.Input(block);
            text.AppendText(decoder.Output);
        }

        private void ProcessingStart()
        {
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (btnStop.Enabled)
            {
                btnStop_Click(null, null);
                formIsClosing = true;
                e.Cancel = true;
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            text.Clear();
        }

        private void cbSource_SelectedValueChanged(object sender, EventArgs e)
        {
            if (((KeyValuePair<int, string>)cbSource.SelectedItem).Key == 100)
            {
                lblFile.Enabled = true;
                textFile.Enabled = true;
                btnFile.Enabled = true;
                btnStart.Visible = false;
                btnStop.Visible = false;
                btnStartF.Visible = true;
                btnStopF.Visible = true;

                btnStartF.Enabled = (textFile.Text.Length > 5);
            }
            else
            {
                lblFile.Enabled = false;
                textFile.Enabled = false;
                btnFile.Enabled = false;
                btnStart.Visible = true;
                btnStop.Visible = true;
                btnStartF.Visible = false;
                btnStopF.Visible = false;
            }
        }

        private void btnFile_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                textFile.Text = openFileDialog1.FileName;
            }
        }

        private async void btnStartF_Click(object sender, EventArgs e)
        {
            textFile.Enabled = false;
            btnFile.Enabled = false;
            checkBoxSaveToFile.Enabled = false;

            btnStartF.Enabled = false;
            btnStopF.Enabled = true;

            decoder.SaveToFile = checkBoxSaveToFile.Checked;
            
            byte[] data = new byte[9600];
            WaveFileReader reader = new WaveFileReader(textFile.Text);

            source = new CancellationTokenSource();
            int numBytesRead;

            while (true)
            {
                if (source.Token.IsCancellationRequested)
                    numBytesRead = 0;
                else
                    numBytesRead = await reader.ReadAsync(data, 0, data.Length, source.Token);

                if (numBytesRead == 0)
                {
                    //need to send at least one empty data block for cases where the audio file does not have any
                    byte[] emptyData = new byte[9600];
                    waveIn_DataAvailable(sender, new WaveInEventArgs(emptyData, emptyData.Length));
                    return;
                }

                waveIn_DataAvailable(sender, new WaveInEventArgs(data, numBytesRead));
            }
        }

        private void btnStopF_Click(object sender, EventArgs e)
        {
            textFile.Enabled = true;
            btnFile.Enabled = true;
            checkBoxSaveToFile.Enabled = true;
            
            btnStopF.Enabled = false;
            btnStartF.Enabled = true;

            source.Cancel();
        }

        private void textFile_TextChanged(object sender, EventArgs e)
        {
            btnStartF.Enabled = (textFile.Text.Length > 5);
        }
    }
}
